package com.boat.framework.common.util;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.core.env.Environment;

import com.boat.framework.common.spring.transaction.TrxTemplate;

import lombok.extern.slf4j.Slf4j;

/**
 * spring工具类
 * 
 * @author 周江
 *
 */
@Slf4j
public class SpringUtils implements ApplicationContextAware, ApplicationEventPublisherAware, InitializingBean {
	private static ApplicationContext context;
	private static ApplicationEventPublisher eventPublisher = null;

	/****** 事务模板bean *******/
	public static final String REQUIRED_TRX_TEMPLATE_BEAN_NAME = "requiredTrxTemplate";
	public static final String REQUIRES_NEW_TRX_TEMPLATE_BEAN_NAME = "requiresNewTrxTemplate";

	@Override
	public void setApplicationContext(ApplicationContext context) throws BeansException {
		SpringUtils.context = context;

		if (log.isDebugEnabled()) {
			log.debug("成功注入ApplicationContext");
		}
	}

	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
		SpringUtils.eventPublisher = eventPublisher;

		if (log.isDebugEnabled()) {
			log.debug("成功注入ApplicationEventPublisher");
		}
	}

	/**
	 * 获取bean对象
	 * 
	 * @param <T>
	 * @param name
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getBean(String name) {
		return (T) context.getBean(name);
	}

	public static <T> T getBean(Class<T> clazz) {
		return context.getBean(clazz);
	}

	public static <T> T getBean(String name, Class<T> clazz) {
		return context.getBean(name, clazz);
	}

	public static String[] getBeanNamesForType(Class<?> type) {
		return context.getBeanNamesForType(type);
	}

	/**
	 * 获取属性
	 */
	public static String getProperty(String key) {
		return context.getEnvironment().getProperty(key);
	}

	public static String getProperty(String key, String defaultValue) {
		return context.getEnvironment().getProperty(key, defaultValue);
	}

	public static String[] getActiveProfiles() {
		return context.getEnvironment().getActiveProfiles();
	}

	/**
	 * 获取环境
	 */
	public static Environment getEnvironment() {
		return context.getEnvironment();
	}

	/**
	 * 使用当前上下文的事务，没有则创建。一般使用这个就够了
	 * 
	 * @return
	 */
	public static TrxTemplate trxTemplate() {
		TrxTemplate transactionTemplate = SpringUtils.getBean(REQUIRED_TRX_TEMPLATE_BEAN_NAME);
		if (transactionTemplate == null) {
			throw new RuntimeException("事务模板不可用，请检查当前项目是否已引入boat-starter-web");
		}
		return transactionTemplate;
	}

	/**
	 * 不管当前上下文有没有事务，总是创建一个新事务
	 * 
	 * @return
	 */
	public static TrxTemplate requiresNewTrxTemplate() {
		TrxTemplate transactionTemplate = SpringUtils.getBean(REQUIRES_NEW_TRX_TEMPLATE_BEAN_NAME);
		if (transactionTemplate == null) {
			throw new RuntimeException("事务模板不可用，请检查当前项目是否已引入boat-starter-web");
		}
		return transactionTemplate;
	}

	public static ApplicationContext getContext() {
		return context;
	}

	/**
	 * 获取事件发布对象
	 * 
	 * @return
	 */
	public static ApplicationEventPublisher getEventPublisher() {
		return eventPublisher;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		log.info("SpringUtils初始化成功");
	}
}